<!--
 * @Description: 自定义表单
 * @Version: 0.0.1
 * @Autor: zhj1214
 * @Date: 2021-06-02 13:41:13
 * @LastEditors: zhj1214
 * @LastEditTime: 2021-06-07 17:17:26
-->
<template>
  <div class="view" :style="customStyle">
    <!-- 头部插槽 -->
    <slot name="formHeader"></slot>
    <!-- 表单部分 -->
    <i-form :ref="formData.formType" :model="refModel" :rules="getRuleList">
      <form-item
        v-for="(item, index) in getList"
        :prop="item.componentsPropName"
        :key="index"
      >
        <component
          v-if="item.type"
          :is="item.type"
          :type="item.type"
          @modelWatch="modelWatch"
        ></component>
        <slot v-else-if="item.slotType" :name="item.slotType"></slot>
      </form-item>
      <!-- 默认底部插槽 -->
      <form-item>
        <slot></slot>
      </form-item>
    </i-form>
  </div>
</template>

<script>
import Vue from "vue";
// const requireComponents = require.context(
//   "./zhjFormComponents",
//   false,
//   /\.vue$/
// );

import formInput from './zhjFormComponents/formInput';
import formRadio from './zhjFormComponents/formRadio';
import formSelect from './zhjFormComponents/formSelect';
import formDatePicker from './zhjFormComponents/formDatePicker';
import formCheckbox from './zhjFormComponents/formCheckbox';
import formTimePicker from './zhjFormComponents/formTimePicker';
import formNumber from './zhjFormComponents/formNumber';

export default {
  name:'dy-form',
  props: {
    // 数据源
    formData: {
      type: Object,
      default: () => {}
    },
    // 父组件样式
    customStyle: {
      type: Object,
      default: () => {}
    }
  },
  components:{
    formInput,
    formRadio,
    formSelect,
    formDatePicker,
    formCheckbox,
    formTimePicker,
    formNumber
  },
  computed: {
    /**
     * @description: 对传入的组件数据进行二次加工，返回需要的数据格式
     * @author: zhj1214
     */
    getList() {
      return this.formData.componentsList;
    },
    getRuleList() {
      return this.ruleList;
    }
  },
  data() {
    return {
      refModel: {}, // formData数据源中所有model值的集合对象，用于表单验证功能
      ruleList: {} // 所有组件校验规则列表
    };
  },
  created() {
    // this.mountedComponent();
    this.initData();
  },
  mounted() {
    this.initComponents();
  },
  methods: {
    /**
     * @description: 动态加载所需组件
     * @author: zhj1214
     */

    mountedComponent() {
      // 遍历出每个组件的路径
      requireComponents.keys().forEach(fileName => {
        // 组件实例
        const reqCom = requireComponents(fileName);
        // 截取路径作为组件名
        const reqComName =
          reqCom.name || fileName.replace(/\.\/(.*)\.vue/, "$1");
          
        this.formData.componentsList.forEach(item => {
          console.log(reqComName, "000000000", item.type);
          if (reqComName.includes(item.type)) {
            // 组件挂载
            Vue.component(reqComName, reqCom.default || reqCom);
          }
        });
      });
    },
    /**
     * @description: 初始化表单数据
     * @author: zhj1214
     */
    initData() {
      this.formData.componentsList.forEach(el => {
        let type = el.type;
        if (!type && el.slotType) type = el.slotType;
        if (type) {
          // 组合 form需要的 数据
          this.$set(this.ruleList, `${type}Model`, el.rules || []);
          this.$set(
            this.refModel,
            `${type}Model`,
            (el.data && el.data.model) || ""
          );
          // 拼接 formItem prop
          el.componentsPropName = `${type}Model`;
        }
      });
    },
    /**
     * @description: 初始化封装的基础组件
     * @author: zhj1214
     */

    initComponents() {
      this.formData.componentsList.forEach((el, index) => {
        if (el.type) {
          this.$children[0].$children[
            index
          ].$children[0].$attrs = this.formData.componentsList[
            index
          ].componentsProps;

          this.$children[0].$children[
            index
          ].$children[0].$listeners = this.formData.componentsList[
            index
          ].function;
          this.$ebs.$emit(el.type, el);
        }
      });
    },
    /**
     * @description: 改变表单，校验 model
     * @param {*} val 需要改变的值  ”对象“
     * @author: zhj1214
     */

    modelWatch(val) {
      let key = "";
      if (Object.keys(val)[0] in this.refModel) {
        key = Object.keys(val)[0];
      }
      this.$set(
        this.refModel,
        key || Object.keys(val)[0],
        val[key || Object.keys(val)[0]]
      );
      if (key) this.$emit("modelChange", this.refModel);
    }
  }
};
</script>
